package com.wpre.lotterysystem.service.Impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.wpre.lotterysystem.common.errcode.ServiceErrorCodeConstants;
import com.wpre.lotterysystem.common.exception.ServiceException;
import com.wpre.lotterysystem.common.utils.JWTUtil;
import com.wpre.lotterysystem.common.utils.RegexUtil;
import com.wpre.lotterysystem.controller.param.ShortMassageLoginParam;
import com.wpre.lotterysystem.controller.param.UserLoginParam;
import com.wpre.lotterysystem.controller.param.UserPasswordLoginParam;
import com.wpre.lotterysystem.controller.param.UserRegisterParam;
import com.wpre.lotterysystem.dao.dataobject.Encrypt;
import com.wpre.lotterysystem.dao.dataobject.UserDO;
import com.wpre.lotterysystem.dao.mapper.UserMapper;
import com.wpre.lotterysystem.service.UserService;
import com.wpre.lotterysystem.service.VerificationCodeService;
import com.wpre.lotterysystem.service.dto.UserDTO;
import com.wpre.lotterysystem.service.dto.UserLoginDTO;
import com.wpre.lotterysystem.service.dto.UserRegisterDTO;
import com.wpre.lotterysystem.service.enums.UserIdentityEnum;
import jakarta.validation.constraints.NotBlank;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: LianBao
 * Date: 2024-12-11
 * Time: 16:42
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private VerificationCodeService verificationCodeService;

    @Override
    public UserRegisterDTO register(UserRegisterParam param) {
        //1.校验注册信息
        checkRegisterInfo(param);

        //2.加密
        UserDO userDO = new UserDO();
        userDO.setUserName(param.getName());
        userDO.setEmail(param.getMail());
        userDO.setIdentity(param.getIdentity());
        userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        if (StringUtils.hasText(param.getPassword())) {
            //如果有密码才设置
            userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }

        //3.存储到数据库
        userMapper.insert(userDO);
        //4.构造返回
        UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
        userRegisterDTO.setUserId(userDO.getId());

        return userRegisterDTO;
    }

    /**
     * 登录
     *
     * @param param
     * @return
     */
    @Override
    public UserLoginDTO login(UserLoginParam param) {
        UserLoginDTO userLoginDTO;

        //1,类型检查和转换
        if (param instanceof UserPasswordLoginParam loginParam) {//java14及以上版本,可以两个操作(类型检查和转换)一起完成
            //如果是密码登录方式
            userLoginDTO = loginByUserPassword(loginParam);
        } else if (param instanceof ShortMassageLoginParam loginParam) {
            userLoginDTO = loginByShortMassage(loginParam);
        } else {
            throw new ServiceException(ServiceErrorCodeConstants.Login_Info_Not_Exist_ERROR);
        }
        return userLoginDTO;
    }

    //根据身份查询人员列表,如果身份信息为空,查询各个人员身份列表
    @Override
    public List<UserDTO> findBaseUserInfo(UserIdentityEnum identity) {
        String identityString =
                identity == null ? null : identity.name();
        //查表
        List<UserDO> userDOList = userMapper.selectUserListByIdentity(identityString);

        List<UserDTO> userDTOList = userDOList.stream().map(
                userDO -> {
                    UserDTO dto = new UserDTO();
                    dto.setUserId(userDO.getId());
                    dto.setUserName(userDO.getUserName());
                    dto.setEmail(userDO.getEmail());
                    dto.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    dto.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
                    return dto;
                }).collect(Collectors.toUnmodifiableList());
        return userDTOList;
    }

    /**
     * 短信登录验证码
     *
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByShortMassage(ShortMassageLoginParam loginParam) {
        if (!RegexUtil.checkMobile(loginParam.getLoginMobile())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //获取用户数据
        UserDO userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginMobile()));
        if (userDO == null) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity()) &&
                !loginParam.getMandatoryIdentity().equals(userDO.getIdentity())) {
            //
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        //校验验证码
        //1.从缓存中获取验证码
        String verificationCode = verificationCodeService.getVerificationCode(loginParam.getLoginMobile());
        if (!loginParam.getVerificationCode().equals(verificationCode)) {
            //如果验证码不相等
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }
        //校验通过
        //塞入返回值
        Map<String, Object> claim = new HashMap<>();
        claim.put("id", userDO.getId());
        claim.put("name", userDO.getUserName());
        claim.put("identity", userDO.getIdentity());
        //生成token

        String token = JWTUtil.genJwt(claim);
        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));

        return userLoginDTO;
    }

    /**
     * 密码登录
     *
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByUserPassword(UserPasswordLoginParam loginParam) {
        UserDO userDO = null;
        //1.判断是手机登录还是邮箱登录
        if (RegexUtil.checkMobile(loginParam.getLoginName())) {
            //手机号登录
            //根据手机号查询用户表
            userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));
        } else if (RegexUtil.checkMail(loginParam.getLoginName())) {
            //邮箱登录
            //根据邮箱查询用户表
            userDO = userMapper.selectByMail(loginParam.getLoginName());
        } else {
            throw new ServiceException(ServiceErrorCodeConstants.Login_Not_Exist_ERROR);
        }
        System.out.println("参数的密码:" + loginParam.getPassword());
        System.out.println("数据库中的密码" + userDO.getPassword());

        //校验登录信息
        if (userDO == null) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity()) &&
                !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {
            //强制身份登录校不验通过
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        } else if (!DigestUtil.sha256Hex(loginParam.getPassword())
                .equals(userDO.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }



        //校验通过
        //塞入返回值
        Map<String, Object> claim = new HashMap<>();
        claim.put("id", userDO.getId());
        claim.put("name", userDO.getUserName());
        claim.put("identity", userDO.getIdentity());
        //生成token
        String token = JWTUtil.genJwt(claim);
        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    //校验注册信息
    private void checkRegisterInfo(UserRegisterParam param) {
        if (param == null) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);//抛一个Service层异常
        }
        //1.校验邮箱格式(xxx@xxx.xxx),通过正则表达式
        if (!RegexUtil.checkMail(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        //2.校验手机号格式
        if (!RegexUtil.checkMobile(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }

        //3.校验身份信息
        if (null == UserIdentityEnum.forName(param.getIdentity())) {
            //如果身份即不是管理员也不是普通用户,抛出一个异常
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //4.校验管理员密码必填
        if (param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())
                && !StringUtils.hasText(param.getPassword())) {
            //如果当前身份是管理员身份,并且如果password没有正文(没有填写密码),抛出一个异常
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY_ERROR);
        }

        //5.密码校验大于6位 -- 这儿 密码小于6位了
        if (StringUtils.hasText(param.getPassword())
                && !RegexUtil.checkPassword(param.getPassword())) {
            //如果密码有正文,并且校验不通过,抛出异常
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        //7.校验邮箱是否被使用过
        if (checkMailUsed(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED_ERROR);
        }

        //6.校验手机是否被使用过
        if (checkPhoneNumberUsed(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED_ERROR);
        }
    }

    //校验手机号是否被使用
    private boolean checkPhoneNumberUsed(String phoneNumber) {
        int result = userMapper.countByPhone(new Encrypt(phoneNumber));
        return result > 0;
    }

    //校验邮箱是否被使用过
    private boolean checkMailUsed(String mail) {
        int result = userMapper.countByMail(mail);
        //从数据库中,通过mail查询,如果个数>0表示使用过
        return result > 0;
    }
}
